/*
 * @Author: zhuxiaoyi
 * @Date: 2024-01-15 17:07:20
 * @LastEditor: zhuxiaoyi
 * @LastEditTime: 2024-04-11 14:42:54
 * @Description:
 */
import { Provide,Config } from '@midwayjs/core';
import { ISldOptions } from '../interface';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Sld } from '../entity/sld.entity';
import { Repository } from 'typeorm';
import * as xml2js from 'xml2js';
import * as fs from 'fs';
import axios from 'axios';
@Provide()
export class SldService {
  @InjectEntityModel(Sld)
  sldModel: Repository<Sld>;

  async saveSld(content: string, options: ISldOptions) {
    let sld = new Sld();
    sld.name = options.name;
    sld.des = options.name;
    sld.isPublished = false;
    sld.content = content;

    const sldResult = await this.sldModel.save(sld);
    if (sldResult) {
      return await this.publishSld(sldResult.id);
    } else {
      return { success: false, message: 'clf文件信息保存失败 '};
    }
  }

  async publishSld(id: number) {
    let firstSld = await this.sldModel.findOne({
      where: {
        id: id,
      },
    });
    return await this.json2xml(firstSld, firstSld.content);
  }

  async readClfFile(clf: any, options: ISldOptions) {
    try {
      // 读取 CLF 文件内容
      const clfXml = fs.readFileSync(clf.data, 'utf-8');
      // 解析 CLF 文件为 JSON 对象
      const clfObj = await this.parseClfXml(clfXml);
      const content = await this.ruleParsing(clfObj);
      return await this.saveSld(content, options);
    } catch (error) {
      return { success: false, message: 'clf文件解析失败 ' + error.message };
    }
  }
  // 解析 CLF 文件为 JSON 对象
  private parseClfXml(clfXml: string): Promise<any> {
    return new Promise((resolve, reject) => {
      xml2js.parseString(clfXml, { trim: true }, (err, result) => {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      });
    });
  }

  private ruleParsing(clfObj) {
    let content = [];
    clfObj.clf.symbol.forEach(element => {
      const { red, green, blue } = element.fillcolor[0].$;
      let color = this.rgbToHex(red, green, blue);
      content.push({
        lowervalue: element.lowervalue[0],
        opacity: element.opacity[0],
        color,
      });
    });

    return JSON.stringify(content);
  }

  private rgbToHex(r, g, b) {
    const redHex = ('0' + parseInt(r).toString(16)).slice(-2);
    const greenHex = ('0' + parseInt(g).toString(16)).slice(-2);
    const blueHex = ('0' + parseInt(b).toString(16)).slice(-2);
    return `#${redHex}${greenHex}${blueHex}`;
  }

  private async json2xml(firstSld: Sld, jsonData: string) {
    const colorMapEntries = JSON.parse(jsonData)
      .map(
        entry =>
          `<sld:ColorMapEntry color="${entry.color}" quantity="${entry.lowervalue}" label="${entry.lowervalue}"/>`
      )
      .join('\n');
    const xmlResult = `<?xml version="1.0" encoding="UTF-8"?>
      <sld:StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:sld="http://www.opengis.net/sld" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" version="1.0.0">
        <sld:NamedLayer>
          <sld:Name>${firstSld.name}</sld:Name>
          <sld:UserStyle>
            <sld:Name>${firstSld.name}</sld:Name>
            <sld:FeatureTypeStyle>
              <sld:Name>name</sld:Name>
              <sld:Rule>
                <sld:RasterSymbolizer>
                  <sld:ChannelSelection>
                    <sld:GrayChannel>
                      <sld:SourceChannelName>1</sld:SourceChannelName>
                      <sld:ContrastEnhancement>
                        <sld:GammaValue>1.0</sld:GammaValue>
                      </sld:ContrastEnhancement>
                    </sld:GrayChannel>
                  </sld:ChannelSelection>
                  <sld:ColorMap type="values">
                    ${colorMapEntries}
                  </sld:ColorMap>
                  <sld:ContrastEnhancement/>
                </sld:RasterSymbolizer>
              </sld:Rule>
            </sld:FeatureTypeStyle>
          </sld:UserStyle>
        </sld:NamedLayer>
      </sld:StyledLayerDescriptor>
    `;
    return await this.fetchSld(xmlResult);
  }

  @Config('geoServerURL')
  geoServerURL;

  async fetchSld(
    sldContent: string
  ): Promise<{ success: boolean; message: string }> {
    try {
      const workspace = 'result';
      const response = await axios.post(
        `${this.geoServerURL}/rest/workspaces/${workspace}/styles`,
        sldContent,
        {
          auth: {
            username: 'admin', // 替换为您的 GeoServer 用户名
            password: 'geoserver', // 替换为您的 GeoServer 密码
          },
          headers: {
            'Content-Type': 'application/vnd.ogc.sld+xml',
          },
        }
      );
      if (response.status === 201) {
        // 请求成功
        return { success: true, message: '渲染文件上传成功' };
      } else {
        // 请求失败
        return { success: false, message: '渲染文件上传失败，失败原因:' };
      }
    } catch (error) {
      // 捕获异常，请求失败
      return {
        success: false,
        message: '渲染文件上传失败，失败原因: '  + error.response.statusText ,
      };
    }
  }
}
